#pragma once
#include"Inet_data.h"

using namespace std;

class Tcp : public nocopy
{
public:
    Tcp(uint16_t port)
        : _port(port)
    {
    }

    void Creat_socket()
    {
        // 1.创建套接字(创建文件细节)
        _sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字(域、套接字类型、协议)参数2基本可以固定tcp/udp
        if (_sockfd < 0)
        {
            cerr << "创建套接字失败" << endl;
            exit(-1);
        }
    }

    void Bind()
    {
        // 2.绑定(网络信息与文件信息相关联)
        struct sockaddr_in local;      //
        local.sin_family = AF_INET;    // 域，用于sockaddr类型接收时的辨别字段
        local.sin_port = htons(_port); // 端口号 主机转网络(用于发送)
        local.sin_addr.s_addr = INADDR_ANY; // 地址任意

        int n = ::bind(_sockfd, (sockaddr *)&local, sizeof(local));
        if (n != 0)
        {
            cerr << "套接字绑定失败!!!" << endl;
        }
    }

    void Listen() // 监听，等待客户端进行connect
    {
        if (listen(_sockfd, 5) == -1) // 参数二是全连接队列
        {
            cerr << "listen fails!!!" << endl;
            exit(-1);
        }
    }

    void Add(const Inet_data& tmp)
    {
        for(const Inet_data& ever:_Inet_list)
        {
            if(ever==tmp)
            {
                break;
            }
        }
        _Inet_list.push_back(tmp);
    }

    void Run() // 返回一个连接套接字，用于网络数据通信
    {
        while (true)
        {
            struct sockaddr_in local;
            socklen_t len;
            _connect_sockfd = accept(_sockfd, (sockaddr *)&local, &len);
            if (_connect_sockfd < 0)
            {
                cout << "accept error ,continue..." << endl;
                continue;
            }
            cout << "成功接收客户端连接..." << endl;
            Inet_data tmp(_connect_sockfd,local);
            Add(tmp);

            tmp.Inet_info();

            pattern_1(tmp);
        }
    }

    ~Tcp()
    {
    }

private:
    int _sockfd; // socket创建的是监听套接字，用于服务器listen
    uint16_t _port;
    uint16_t _connect_sockfd; // 用于网络通信的连接套接字
    vector<Inet_data> _Inet_list;

private:
    void Thread_run(uint16_t sockfd,const Inet_data& tmp)
    {
        
        while (true)
        {
            // 数据读取
            char buffer[1024];
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
            }
            else if (n == 0) // 对端关闭连接
            {
                cout << "客户端关闭连接，读取完毕..." << endl;
                break;
            }
            else
            {
                cerr << "读取失败..." << endl;
                break;
            }
            cout << "server reading:" << buffer <<"->";
            tmp.Inet_info();
            
            // 数据返回
            for(const Inet_data& ever:_Inet_list)
            {
                write(ever.get_sockfd(), buffer, n);
            }
        }
    }
    void pattern_1(const Inet_data& tmp) // 多线程通信
    {
        //主线程不断accept，然后为每一个客户端创建一个新线程进行通信
        thread t(std::bind(&Tcp::Thread_run,this,placeholders::_1,placeholders::_2),_connect_sockfd,tmp);
        //传入连接描述符，防止主线程在新线程通信时先执行了accept从而导致更改了_connect_sockfd
        t.detach();//线程分离
    }
};